﻿#region [ License information          ]
/* ************************************************************
 *
 * Copyright (c) Bjørn Bouet Smith, 2010, 2011
 *
 * This source code is subject to terms and conditions of 
 * Microsoft Public License (Ms-PL).
 * 
 * A copy of the license can be found in the license.txt
 * file at the root of this distribution. If you can not 
 * locate the License, please send an email to bjornsmith@gmail.com
 * 
 * By using this source code in any fashion, you are 
 * agreeing to be bound by the terms of the Microsoft 
 * Public License.
 *
 * You must not remove this notice, or any other, from this
 * software.
 *
 * ************************************************************/
#endregion

using System;
using System.Collections.Generic;

namespace Smith.AMC
{
    /// <summary>
    /// Memcached client that will use asynchronous operations to connect to the memcached server(s) 
    /// and do all its operations.
    /// It is asynchronous because its the most efficient way of handling the latency involved in 
    /// doing out of process operations.
    /// 
    /// If synchronous operations is needed, it is possible to wrap a synchronous implementation around the
    /// asynchronous implementation of the client.
    /// 
    /// i.e.
    /// <code>
    /// IMemcachedClient client = new SyncClientImplementation();
    /// Exception exceptionThrownByCache = null;
    /// ManualResetEvent resetEvent = new ManualResetEvent(false);
    /// client.BeginAdd(
    ///     cacheItem,
    ///     ar =>
    ///        {
    ///            ManualResetEvent evt = (ManualResetEvent)ar.AsyncState;
    ///         try
    ///         {
    ///             client.EndAdd(ar);
    ///         }
    ///         catch (Exception e)
    ///         {
    ///             exceptionThrownByCache = e;
    ///         }
    ///         finally
    ///         {
    ///             evt.Set();
    ///         }
    ///     }, resetEvent);
    ///    
    /// resetEvent.WaitOne();
    /// 
    /// if (exceptionThrownByCache != null)
    /// {
    ///     throw exceptionThrownByCache;
    /// }
    /// </code>
    /// 
    /// But it is NOT recommended - your application will suffer from it.
    /// </summary>
    public interface IMemcachedClient : IDisposable
    {
        /// <summary>
        /// Begins an asynchronous add operation against the memcached server.
        /// This operation will only add the item to the cache if it does not already exist
        /// </summary>
        /// <typeparam name="T">The type of data to add</typeparam>
        /// <param name="cacheItem">The item to cache.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginAdd operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginAdd<T>(ICacheItem<T> cacheItem, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous add operation
        /// </summary>
        /// <typeparam name="T">Type of item added</typeparam>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>true if the add operation was a success; false otherwise</returns>
        bool EndAdd<T>(IAsyncResult asyncResult);

        /// <summary>
        /// Begins an asynchronous replace operation against the memcached server.
        /// This operation will only replace the item in the cache not already exist
        /// </summary>
        /// <typeparam name="T">The type of data to replace.</typeparam>
        /// <param name="cacheItem">The item to replace.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginReplace operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginReplace<T>(ICacheItem<T> cacheItem, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous replace operation
        /// </summary>
        /// <typeparam name="T">The type of data to replace</typeparam>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>true if the replace operation was a success: false otherwise</returns>
        bool EndReplace<T>(IAsyncResult asyncResult);

        /// <summary>
        /// Begins an asynchronous remove operation against the memcached server.
        /// This operation will only remove the item in the cache if it exists.
        /// No exceptions will be thrown if the item does not exist
        /// </summary>
        /// <param name="cacheKey">The cacheKey of the item to replace.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginRemove operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginRemove(string cacheKey, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous remove operation
        /// </summary>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>true if the remove operation was a success; false otherwise</returns>
        bool EndRemove(IAsyncResult asyncResult);

        /// <summary>
        /// Begins an asynchronous get operation against the memcached server.
        /// No exceptions will be thrown if the item does not exist
        /// </summary>
        /// <typeparam name="T">the type of data to replace</typeparam>
        /// <param name="cacheKey">The cacheKey of the item to replace.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginGet operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginGet<T>(string cacheKey, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous get operation
        /// </summary>
        /// <typeparam name="T">The type of item to retrieve.</typeparam>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>A cache item with the cached value; or null if no item could be found 
        /// with the cachekey given in the BeginGet operation</returns>
        ICacheItem<T> EndGet<T>(IAsyncResult asyncResult);

        /// <summary>
        /// Begins an asynchronous gets operation against the memcached server.
        /// The difference between get and gets is that gets will return the CAS value for the cache item.
        /// So only use this method if you intend to use the CAS value for a CAS operation.
        /// No exceptions will be thrown if the item does not exist
        /// </summary>
        /// <typeparam name="T">the type of data to replace</typeparam>
        /// <param name="cacheKey">The cacheKey of the item to replace.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginGet operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginGets<T>(string cacheKey, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous gets operation
        /// </summary>
        /// <typeparam name="T">The type of item to retrieve.</typeparam>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>A cache item with the cached value; or null if no item could be found 
        /// with the cachekey given in the BeginGets operation</returns>
        ICacheItem<T> EndGets<T>(IAsyncResult asyncResult);

        /// <summary>
        /// Begins an asynchronous append operation against the memcached server.
        /// </summary>
        /// <typeparam name="T">The type of data to append to the item if found in the cache.</typeparam>
        /// <param name="cacheItem">The cache item.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginAppend operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginAppend<T>(ICacheItem<T> cacheItem, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous append operation
        /// </summary>
        /// <typeparam name="T">The type of data to append.</typeparam>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>
        /// true if the append operation was a success; false otherwise
        /// </returns>
        bool EndAppend<T>(IAsyncResult asyncResult);

        /// <summary>
        /// Begins an asynchronous prepend operation against the memcached server.
        /// </summary>
        /// <typeparam name="T">The type of data to prepend to the item if found in the cache.</typeparam>
        /// <param name="cacheItem">The cache item.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginPreAppend operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginPreAppend<T>(ICacheItem<T> cacheItem, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous prepend operation
        /// </summary>
        /// <typeparam name="T">The type of data to prepend.</typeparam>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>
        /// true if the prepend operation was a success; false otherwise
        /// </returns>
        bool EndPreAppend<T>(IAsyncResult asyncResult);

        /// <summary>
        /// Begins an asynchronous multi Check and Set operation against the memcached server.
        /// Check and Set means replace the item in the cache with this item, except if someone else
        /// modified it in the mean time.
        /// CASValue must be set on the cacheItem, otherwise this operation will fail
        /// </summary>
        /// <typeparam name="T">The type of data the cache item represents</typeparam>
        /// <param name="cacheItem">The cache item to replace.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginCheckAndSet operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginCheckAndSet<T>(ICacheItem<T> cacheItem, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous Check and Set operation
        /// </summary>
        /// <typeparam name="T">The type of data to check and set</typeparam>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>
        /// true if the cas operation was a success; false otherwise
        /// </returns>
        bool EndCheckAndSet<T>(IAsyncResult asyncResult);

        /// <summary>
        /// Begins an asynchronous multi get operation against the memcached server.
        /// This operation will return a collection of cache items with the items that existed in the cache.
        /// </summary>
        /// <typeparam name="T">The type of data to retrieve.
        /// All cache keys should represent data of the same type</typeparam>
        /// <param name="cacheKeys">The cache keys of the items to retrieve.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginGetMultiple operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginGetMultiple<T>(ICollection<string> cacheKeys, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous multi get operation
        /// </summary>
        /// <typeparam name="T">The type of data to get</typeparam>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>
        /// A collection with the items found in the cache; if no items was found an empty collection is returned
        /// </returns>
        ICollection<ICacheItem<T>> EndGetMultiple<T>(IAsyncResult asyncResult);

        /// <summary>
        /// Begins an asyncronous operation for setting the initial value of a cache key.
        /// This operation should be called prior to using either Increment or Decrement.
        /// </summary>
        /// <param name="cacheKey">The cache key.</param>
        /// <param name="initialValue">The initial value to set in the server.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginSetValueForIncrement operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginSetValueForIncrement(string cacheKey, ulong initialValue, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous operation for setting the initial value for a cache key
        /// </summary>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>
        /// true if the initial setting of the value was a success; false otherwise
        /// </returns>
        bool EndSetValueForIncrement(IAsyncResult asyncResult);

        /// <summary>
        /// Begins an asyncronous increment operation.
        /// </summary>
        /// <param name="cacheKey">The cache key.</param>
        /// <param name="incrementBy">The value to increment the existing value by.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginIncrement operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginIncrement(string cacheKey, ulong incrementBy, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous increment operation.
        /// </summary>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>
        /// The incremented value from the cache; or 0 (zero) if no existing key could be found
        /// </returns>
        ulong EndIncrement(IAsyncResult asyncResult);

        /// <summary>
        /// Begins an asyncronous decrement operation.
        /// </summary>
        /// <param name="cacheKey">The cache key.</param>
        /// <param name="decrementBy">The value to decrement the existing value by.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginIncrement operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginDecrement(string cacheKey, ulong decrementBy, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous decrement operation.
        /// </summary>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>
        /// The decremented value from the cache; or 0 (zero) if no existing key could be found
        /// </returns>
        ulong EndDecrement(IAsyncResult asyncResult);

        /// <summary>
        /// Begins an asynchronous set operation against the memcached server.
        /// This operation will unconditionally set the value, no matter if there is already another values present.
        /// </summary>
        /// <typeparam name="T">The type of data to set</typeparam>
        /// <param name="cacheItem">The item to cache.</param>
        /// <param name="callback">The <see cref="System.AsyncCallback"/> delegate that is executed when the BeginSet operation completes</param>
        /// <param name="state">An object that contains any additional user-defined data.</param>
        /// <returns>
        /// An <see cref="System.IAsyncResult"/> that represents the asynchronous call.
        /// </returns>
        IAsyncResult BeginSet<T>(ICacheItem<T> cacheItem, AsyncCallback callback, object state);

        /// <summary>
        /// Handles the end of the asynchronous set operation
        /// </summary>
        /// <typeparam name="T">Type of item set</typeparam>
        /// <param name="asyncResult">An <see cref="System.IAsyncResult"/> that represents the asynchronous call.</param>
        /// <returns>true if the set operation was a success; false otherwise</returns>
        bool EndSet<T>(IAsyncResult asyncResult);
    }
}
